package Controllers;

import Connection.User;
import Entities.Advantages.IAdvantage;
import Entities.Ball;
import Entities.Bar;
import Entities.Brick;
import Entities.Drawable;
import Entities.Missile;
import Entities.Phase;
import StateInformation.GameState;
import Visitor.BallCollisionVisitor;
import Visitor.BarCollisionVisitor;
import Visitor.IVisitor;
import Visitor.MoveVisitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Timer;

public class AnimationController extends Thread {

    private Phase phase;
    private ArrayList<Ball> ballList;
    private Bar bar;
    private boolean rigthPressed = false;
    private boolean leftPressed = false;
    private boolean spacePressed = false;
    private int maxWidth;
    private PhaseController phaseController;
    private boolean stop;
    private Timer timer;
    private boolean gameStarted;
    private AdvantageController advantageController;
    private GameState gameState;

    public AnimationController(Phase phase, Bar bar, Ball ball, int maxWidth, PhaseController phaseController, User user) {
        this.gameState = user.getGameState();
        this.phase = phase;
        this.phaseController = phaseController;
        this.bar = bar;
        this.maxWidth = maxWidth;

        ballList = new ArrayList<>();
        ballList.add(ball);
        stop = false;

        timer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                gameState.increaseTime();
            }
        });

        gameStarted = false;
    }

    @Override
    public void run() {
        startAdvantageController();
        while (!stop) {
            try {
                controlTimer();
                treatAdvantage();
                synchronized (ballList) {
                    for (Ball b : ballList) {
                        treatCollisionsOfBall(b);
                    }
                    treatMovementOfElements();
                    killBallsBelowBar();
                    isPhaseFinished();
                }
                Thread.sleep(5);

                //cleanPhase();
            } catch (InterruptedException ex) {
                Logger.getLogger(AnimationController.class.getName()).log(Level.SEVERE, null, ex);
                System.out.println("AnimationController::run");
            }
        }
        timer.stop();
    }

    public void setRigthPressed(boolean rigthPressed) {
        this.rigthPressed = rigthPressed;
    }

    public void setLeftPressed(boolean leftPressed) {
        this.leftPressed = leftPressed;
    }

    public void setSpacePressed(boolean spacePressed) {
        this.spacePressed = spacePressed;
    }

    private void killBallsBelowBar() {
        int i = -1;
        synchronized (ballList) {
            for (Ball ball : ballList) {
                if (ball.getY() > bar.getY()) {
                    i = ballList.indexOf(ball);
                }
            }
            synchronized (phase) {
                if (i != -1) {
                    phase.remove(ballList.get(i));
                    ballList.remove(i);
                    if (ballList.isEmpty()) {
                        gameState.setNumberOfLifes(gameState.getNumberOfLifes() - 1);
                    }
                }
            }
        }
    }

    private void startAdvantageController() {
        advantageController = new AdvantageController(phase);
        advantageController.setBallList(ballList);
        advantageController.setBar(bar);
        advantageController.start();
    }

    private void treatAdvantage() {
        Drawable drawable = null;
        IVisitor barCollisionVisitor = new BarCollisionVisitor(bar);
        synchronized (phase) {
            drawable = phase.accept(barCollisionVisitor);
        }
        if (drawable != null) {
            IAdvantage a = (IAdvantage) drawable;
            a.setStartTime(System.currentTimeMillis());
            advantageController.addAdvantage(a);
            synchronized (phase) {
                phase.remove(drawable);
            }
        }
    }

    private void treatMovementOfElements() {
        IVisitor moveVisitor = new MoveVisitor(leftPressed, rigthPressed, spacePressed, maxWidth);
        synchronized (phase) {
            phase.accept(moveVisitor);
        }
    }

    private void treatCollisionsOfBall(Ball b) {
        IVisitor ballCollisionVisitor = new BallCollisionVisitor(b);
        Drawable drawable = phase.accept(ballCollisionVisitor);
        if (drawable != null && drawable instanceof Brick) {
            Brick brick = (Brick) drawable;
            if (brick.getResistance() == 0) {
                if (brick.getAdvantage() != null) {
                    synchronized (phase) {
                        phase.addChild(brick.getAdvantage());
                    }
                    brick.getAdvantage().setDy(1);
                }
                synchronized (phase) {
                    phase.remove(drawable);
                }
            } else {
                brick.setResistance(brick.getResistance() - 1);
            }
            gameState.setScore(gameState.getScore() + brick.getScore());
        }
    }

    private void isPhaseFinished() {
        ArrayList<Brick> brickList = new ArrayList<>();
        synchronized (phase) {
            for (int i = 0; i < phase.getNumElems(); i++) {
                if (phase.getChild(i) instanceof Brick) {
                    Brick brick = (Brick) phase.getChild(i);
                    brickList.add(brick);
                }
            }
            if (ballList.isEmpty() || brickList.isEmpty()) {
                if (gameState.getNumberOfLifes() == 0) {
                    phaseController.gameOver();
                } else if (brickList.isEmpty()) {
                    gameState.setFinalLevel("");
                    phaseController.finish();
                } else {
                    Ball ball = new Ball(220, 500, 0, 0, 8);
                    phase.addChild(ball);
                    ballList.add(ball);
                    bar.setX(192);
                    phaseController.ballLost();
                    gameStarted = false;
                    timer.stop();
                }
            }
        }
    }

    private void cleanPhase() {
        for (int i = 0; i < phase.getNumElems(); i++) {
            if (phase.getChild(i) instanceof Missile || phase.getChild(i) instanceof IAdvantage) {
                if (phase.getChild(i).getX() < -5 || phase.getChild(i).getX() > 465) {
                    phase.remove(phase.getChild(i));
                }
                if (phase.getChild(i).getY() < -5 || phase.getChild(i).getX() > 585) {
                    phase.remove(phase.getChild(i));
                }
            }
        }
    }

    public void setTerminar(boolean stop) {
        this.stop = stop;
        advantageController.setStop(true);
    }

    private void controlTimer() {
        if (spacePressed) {
            gameStarted = true;
            timer.start();
        }
        if (!gameStarted) {
            timer.stop();
        }
    }
}
